package com.badqiu.datamodifier;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * 数据类型修饰工具类,可以将一种类型的数据修饰为另一种类型的数据 如String => Integer,String => Date的转换 例1：将String转为Integer, 表达式为var?int
 * 例2：使用多个修饰，表达式为var?string?int 例3: 为修饰传递参数,表达式为var?date(yyyy-MM-dd)
 * 
 * @author badqiu
 */
public class DataModifierBean
{
    
    private static final String DATA_MODIFIER_OPERATOR = "?";
    
    private Map<String, DataModifier> modifiers = new HashMap<>();
    
    public DataModifierBean()
    {
    }
    
    public void registerDataModifier(String modifierName, DataModifier modifier)
    {
        modifiers.put(modifierName, modifier);
    }
    
    public void deregisterDataModifier(String modifierName)
    {
        modifiers.remove(modifierName);
    }
    
    public Map<String, DataModifier> getAvailableDataModifiers()
    {
        return Collections.unmodifiableMap(modifiers);
    }
    
    public static String getModifyVariable(String completeExpression)
    {
        int index = completeExpression.indexOf(DATA_MODIFIER_OPERATOR);
        if (index == -1)
            return completeExpression;
        return completeExpression.substring(0, index);
    }
    
    public Object modify(String completeExpression, Object dataModifyValue)
    {
        int index = completeExpression.indexOf(DATA_MODIFIER_OPERATOR);
        if (index == -1)
        {
            return dataModifyValue;
        }
        String dataModifierExpression = completeExpression.substring(index);
        try
        {
            return directModify0(dataModifierExpression, dataModifyValue);
        }
        catch (DataModifierException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new DataModifierException("cannot modify value:" + dataModifyValue + " with completeExpression:" + completeExpression, e);
        }
    }
    
    /**
     * @param dataModifierExpression Syntax = ?modifier1?modifier2(modifierArgument2)...
     * @param dataModifyValue
     * @return
     * @throws Exception
     */
    public Object directModify(String dataModifierExpression, Object dataModifyValue)
    {
        try
        {
            return directModify0(dataModifierExpression, dataModifyValue);
        }
        catch (DataModifierException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new DataModifierException("cannot modify value:" + dataModifyValue + " with expression:" + dataModifierExpression, e);
        }
    }
    
    private Object directModify0(String dataModifierExpression, Object dataModifyValue)
        throws Exception
    {
        if (isEmptyString(dataModifierExpression))
        {
            return dataModifyValue;
        }
        if (!dataModifierExpression.startsWith(DATA_MODIFIER_OPERATOR))
        {
            throw new DataModifierSyntaxException("Syntax error,DataModifier expression must start with [" + DATA_MODIFIER_OPERATOR + "]. auctal:" + dataModifierExpression);
        }
        
        StringTokenizer tokenizer = new StringTokenizer(dataModifierExpression, DATA_MODIFIER_OPERATOR);
        Object result = dataModifyValue;
        while (tokenizer.hasMoreElements())
        {
            String singleExpression = (String)tokenizer.nextElement();
            String modifierName = singleExpression;
            String modifierArgument = null;
            int index = -1;
            if ((index = singleExpression.indexOf("(")) != -1)
            {
                if (!singleExpression.endsWith(")"))
                {
                    throw new DataModifierSyntaxException("Syntax error,modifierArguments must wrap with '(arg1,arg2)'");
                }
                modifierName = modifierName.substring(0, index);
                modifierArgument = singleExpression.substring(index + 1, singleExpression.length() - 1);
            }
            
            DataModifier dataModifier = modifiers.get(modifierName);
            if (dataModifier == null)
            {
                throw new DataModifierSyntaxException("not found DataModifier with give name[" + modifierName + "],available modifier names:" + modifiers.keySet());
            }
            result = dataModifier.modify(result, modifierArgument);
        }
        return result;
    }
    
    private static boolean isEmptyString(String str)
    {
        return (str == null || str.length() == 0);
    }
    
}
